package com.robotic.sensor.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.Arrays;

@Component
@Slf4j
public class ModbusTcpIoServer {
    // 1. 设置服务器监听的端口
    private static final int LISTEN_PORT = 2545;
    // 2. 设置服务器监听的IP地址
    private static final String LISTEN_HOST = "192.168.201.73";

    // 3. (已修改) 新的16进制指令
    // 01 = 从站ID
    // 06 = 功能码 (写单个寄存器)
    // 00 00 = 寄存器地址 (继电器 1)
    // 00 01 = 寄存器值 (ON)
    // 48 0A = CRC16 校验
    // (继电器1) 开门信号
    private static final String HEX_COMMAND_Y1 = "010600000001480A";
    private static final String HEX_COMMAND_Y1_OFF = "01060000000089CA";


    private static final String HEX_COMMAND_Y2 = "01060001000119CA";
    private static final String HEX_COMMAND_Y2_OFF = "010600010000D80A";

    public String sendRelayCommand(String command) {
        String HEX_COMMAND = "1".equals(command) ? HEX_COMMAND_Y1 : HEX_COMMAND_Y2;
        String infoLog = null;
        switch (command) {
            case "1":
                HEX_COMMAND = HEX_COMMAND_Y1;
                infoLog = "已成功发送【打开继电器Y1】指令";
                break;
            case "2":
                HEX_COMMAND = HEX_COMMAND_Y1_OFF;
                infoLog = "已成功发送【停止打开继电器Y2】指令";
                break;
            case "3":
                HEX_COMMAND = HEX_COMMAND_Y2;
                infoLog = "已成功发送【关闭继电器Y3】指令";
                break;
            case "4":
                HEX_COMMAND = HEX_COMMAND_Y2_OFF;
                infoLog = "已成功发送【停止关闭继电器Y4】指令";
                break;
        }

        String result = null;
        String listenAddress = LISTEN_HOST + ":" + LISTEN_PORT;
        log.info("启动TCP服务器 (用于继电器-写操作)，在 " + listenAddress + " 上监听...");

        // 1. 开始监听 (使用 try-with-resources 自动关闭 ServerSocket)
        try (ServerSocket serverSocket = new ServerSocket(LISTEN_PORT, 50, InetAddress.getByName(LISTEN_HOST))) {

            // 2. 等待模块连接
            log.info("等待 '485转WIFI' 模块连接...");
            // (使用 try-with-resources 自动关闭 clientSocket)
            try (Socket clientSocket = serverSocket.accept()) {

                // 3. 模块已连接
                log.info("模块已连接! 模块地址: " + clientSocket.getRemoteSocketAddress());

                // 4. 解码16进制指令为字节
                byte[] bytesToSend = hexStringToByteArray(HEX_COMMAND);

                // 获取输入输出流
                OutputStream out = clientSocket.getOutputStream();
                InputStream in = clientSocket.getInputStream();

                // 5. 发送指令给模块
                log.info("正在发送写命令: " + HEX_COMMAND);
                out.write(bytesToSend);
                out.flush(); // 确保数据立即发送

                // 6. 等待并读取传感器的响应 (设置5秒超时)
                log.info("等待传感器响应...");
                clientSocket.setSoTimeout(5000); // 5000 毫秒 = 5 秒

                byte[] buffer = new byte[64]; // 创建一个缓冲区
                int n = in.read(buffer); // 读取数据

                if (n == -1) {
                    log.info("错误：连接已由模块关闭。");
                    return null;
                }

                // 7. (已修改) 打印和解析 "写" 操作的响应
                byte[] responseBytes = Arrays.copyOf(buffer, n);
                String responseHex = bytesToHexString(responseBytes);

                log.info("收到 %d 字节的原始响应 (16进制): %s%n", n, responseHex);

                // --- 尝试解析响应 ---
                // 预期响应 (写操作成功): 设备会原样返回发送的指令 [01 06 00 00 00 01 48 0A]
                // 总共 8 字节
                int expectedLength = HEX_COMMAND.length() / 2;
                if (n == expectedLength && responseHex.equalsIgnoreCase(HEX_COMMAND)) {
                    log.info("==================== 测试成功 ====================");
                    log.info("  响应与发送的命令一致。");
                    log.info("  >>> " + infoLog + "。");
                    result = infoLog;
                } else {
                    log.info("==================== 测试失败 ====================");
                    log.info("  未收到预期的响应 (期望 %d 字节, 收到 %d 字节)。%n", expectedLength, n);
                    log.info("  期望: %s%n", HEX_COMMAND);
                    log.info("  收到: %s%n", responseHex);
                    result = "未收到预期的响应";
                }

            } // clientSocket 在这里自动关闭
        } catch (SocketTimeoutException e) {
            log.error("错误：读取响应超时: {}", e.getMessage()); // 如果再次超时，请看下面的 "重要排查"
        } catch (IOException e) {
            // 捕获所有其他IO错误 (如监听失败, 接受失败, 读/写失败)
            log.error("发生IO错误: {}", e.getMessage());
            e.printStackTrace();
        }
        // serverSocket 在这里自动关闭
        return result;
    }

    /**
     * 辅助方法：将16进制字符串转换为byte数组
     */
    public static byte[] hexStringToByteArray(String s) {
        int len = s.length();
        if (len % 2 != 0) {
            throw new IllegalArgumentException("16进制字符串长度必须为偶数");
        }
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                    + Character.digit(s.charAt(i + 1), 16));
        }
        return data;
    }

    /**
     * 辅助方法：将byte数组转换为16进制字符串
     */
    public static String bytesToHexString(byte[] bytes) {
        StringBuilder sb = new StringBuilder(bytes.length * 2);
        for (byte b : bytes) {
            sb.append(String.format("%02X", b));
        }
        return sb.toString();
    }
}
